﻿/*
** Xin YUAN, 2023, BSD (2)
*/

////////////////////////////////////////////////////////////////////////////////

#include "base/_w_thread_pool.h"

////////////////////////////////////////////////////////////////////////////////

//work_data_base

class work_data_base
{
private:
	void* pv;
	PTP_WORK pWork;

protected:
	work_data_base() noexcept : pv(NULL), pWork(NULL)
	{
	}
	work_data_base(const work_data_base&) = delete;
	~work_data_base() noexcept
	{
	}
	work_data_base& operator=(const work_data_base&) = delete;

private:
	friend class task_base;
};

//task_base

class task_base : public _w_thread_pool_base
{
private:
	typedef _w_thread_pool_base  baseClass;

protected:
	task_base() noexcept
	{
	}
	task_base(const task_base&) = delete;
	~task_base() noexcept
	{
	}

	task_base& operator=(const task_base&) = delete;

protected:
	bool init(task_util::task_callback cb) noexcept
	{
		//callback
		m_util.callback = cb;
		if ( !baseClass::init() )
			return false;
		return true;
	}

public:
	//Do not reuse work_data_base after calling this method
	void Shutdown() noexcept
	{
		baseClass::dump();
	}

	bool SubmitWork(work_data_base* pw) noexcept
	{
		assert( is_valid() );
		LONG lOrg = ::InterlockedCompareExchange(&m_lExit, 1, 1);
		if ( lOrg == 1 )
			return true;
		//work object
		if ( pw->pWork == NULL ) {
			PTP_WORK pWork = ::CreateThreadpoolWork(&work_callback, pw, &m_cbe);
			if ( pWork == NULL ) //::GetLastError()
				return false;
			pw->pWork = pWork;
		}
		//submit
		pw->pv = this;
		::SubmitThreadpoolWork(pw->pWork);
		return true;
	}

private:
//callbacks
	static VOID CALLBACK work_callback(
					PTP_CALLBACK_INSTANCE Instance,
					PVOID                 Context,
					PTP_WORK              Work
					) noexcept
	{
		work_data_base* pw = (work_data_base*)Context;
		task_base* pThis = (task_base*)(pw->pv);
		pThis->m_util.callback(pw, pThis);
	}

private:
	task_util m_util;
};

////////////////////////////////////////////////////////////////////////////////
